package cloud.xlh.infrastructure.utils;

import com.google.common.collect.*;
import org.springframework.beans.BeanUtils;

import java.lang.reflect.Field;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 *
 * @ project name : xlh_osms
 * @ Author: XuLeHuang
 * @ Date: 2023/2/19 10:57
 * @ Description:
 */
public class MapUtil {

    /**
     *
     * @param key1 rowKey
     * @param key2 columnKey
     * @param value
     * @return com.google.common.collect.Table
     * @author XuLeHuang
     * @create 2023/2/19
     * @name: 双键Map
     * @Description:
     **/
    public static Table doubleKeyMap(Object key1 , Object key2 , Object value ) {
        Table<Object,Object,Object> table= HashBasedTable.create();
        table.put(key1, key2, value);
        return table;
    }

    private final static Map<String, Integer> keyTypeMap = new HashMap<>();
    static {
        keyTypeMap.put("rowKey" , 0);
        keyTypeMap.put("columnKey" , 1);
    }

    /**
     *
     * @param table
     * @param keyTypeCode
     * @return java.util.Set
     * @author XuLeHuang
     * @create 2023/2/19
     * @name: 获取key的集合
     * @Description: key的集合是不包含重复元素的，value集合则包含了所有元素并没有去重；keyTypeCode必传
     **/
    public static Set getKeySet(Table table , Integer keyTypeCode) {
        if (table == null) {
            throw new RuntimeException("table数据源 must be not null");
        }
        Set set = new HashSet<>();
        if (keyTypeCode == keyTypeMap.get("rowKey")) {
             return set = table.rowKeySet();
        } else if (keyTypeCode == keyTypeMap.get("columnKey")) {
            return set = table.columnKeySet();
        } else {
            throw new RuntimeException("keyType must be not null");
        }
    }

    /**
     *
     * @param table
     * @return java.lang.Integer
     * @author XuLeHuang
     * @create 2023/2/19
     * @name:
     * @Description: 计算rowKey对应的value的总和
     **/
    public static Integer calculateSumOfValueByRowKey(Table table) {
        if (table == null) {
            throw new RuntimeException("table数据源 must be not null");
        }
        for (Object key : table.rowKeySet()) {
            Set<Map.Entry<Object, Integer>> rows = table.row(key).entrySet();
            int total = 0;
            for (Map.Entry<Object, Integer> row : rows) {
                total += row.getValue();
            }
            System.out.println(key + ": " + total);
            return total;
        }
        return 0;
    }

    /**
     *
     * @param table
     * @param keyTypeCode
     * @return java.util.Map<java.lang.Object, java.util.Map < java.lang.Object, java.lang.Object>>
     * @author XuLeHuang
     * @create 2023/2/19
     * @name: 双键Map转普通嵌套Map
     * @Description: keyTypeCode必传
     **/
    public static Map<Object, Map<Object, Object>> transformToNestingMap(Table table , Integer keyTypeCode) {
        if (table == null) {
            throw new RuntimeException("table数据源 must be not null");
        }
        if (keyTypeCode == keyTypeMap.get("rowKey")) {
            return table.rowMap();
        } else if (keyTypeCode == keyTypeMap.get("columnKey")) {
            return table.columnMap();
        } else {
            throw new RuntimeException("keyType must be not null");
        }
    }

    /**
     *
     * @param sourceBiMap
     * @param value
     * @return java.lang.Object
     * @author XuLeHuang
     * @create 2023/2/19
     * @name:
     * @Description: 根据value获取key；不影响原来bigMap
     **/
    public Object getValueByKey(HashBiMap<Object, Object> sourceBiMap , Object value) {
        if (sourceBiMap == null) {
            throw new RuntimeException("table数据源 must be not null");
        }
        HashBiMap<Object, Object> targetBiMap = HashBiMap.create();
        BeanUtils.copyProperties(sourceBiMap , targetBiMap);
        BiMap<Object, Object> inverseBiMap = targetBiMap.inverse();
        return inverseBiMap.get(value);
    }

    /**
     *
     * @param map
     * @param value
     * @param valueClassType
     * @return java.lang.Object
     * @author XuLeHuang
     * @create 2023/2/19
     * @name:
     * @Description: 根据value获取key，value不为String类型valueClassType可置空
     **/
    public static Object getValueByKey(Map<Object, Object> map , Object value , Class valueClassType) {
        Set<Map.Entry<Object, Object>> entries = map.entrySet();
        String valueToString = "";
        if (valueClassType != null && "String".equals(valueClassType.getSimpleName())) {
             valueToString = (String) value;
        }
        Iterator<Map.Entry<Object, Object>> iterator = entries.iterator();
        while (iterator.hasNext()) {
            Map.Entry<Object, Object> next = iterator.next();
            Object targetValue = next.getValue();
            if (!valueToString.equals(valueToString) && valueToString.equals((String)targetValue)) {
                return next.getKey();
            } else if (value == targetValue){
                return next.getKey();
            }
        }
        return null;
    }

    /**
     *
     * @return com.google.common.collect.Multimap<java.lang.Object, java.lang.Object>
     * @author XuLeHuang
     * @create 2023/2/19
     * @name: 获取 一key多value Map
     * @Description: 将一个键映射到多个值上
     **/
    public static Multimap<Object ,Object> getSingleKeyMultiValueMap() {
        Multimap<Object, Object> multimap = ArrayListMultimap.create();
        return multimap;
    }

    /**
     *
     * @param o 待转化的java对象
     * @return java.util.Map
     * @author XuLeHuang
     * @create 2023/2/21
     * @name:
     * @Description:  将java对象转成Map
     **/
    public static Map javaObjectToMap(Object o) {
        if (o == null) {
            return new HashMap();
        }
        Map map = new HashMap<>();
        Class<?> aClass = o.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            declaredField.setAccessible(true);
            try {
                map.put(declaredField.getName() , declaredField.get(o));
            } catch (IllegalAccessException e) {
                declaredField.setAccessible(false);
                e.printStackTrace();
                throw new RuntimeException("java对象转成Map异常");
            }
            declaredField.setAccessible(false);
        }
        return map;
    }
}
